package com.chenl.provider.DEMOS.日志相关.全链路日志以及Spring线程池装饰器的使用;

import com.alibaba.fastjson.JSONObject;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.util.*;

@Slf4j
@Aspect
//@Component
public class LogExporterAspect {
    public static void main(String[] args) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes){
            System.out.println(1);
        }

    }
    @Around("@annotation(com.chenl.provider.DEMOS.日志相关.全链路日志以及Spring线程池装饰器的使用.LogAspect)")
    public Object methodExporter(ProceedingJoinPoint joinPoint) throws Throwable{
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        LogThreadLocal.setURI(request.getRequestURI());
        long startTime = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        BigDecimal exeTime = new BigDecimal(endTime).subtract(new BigDecimal(startTime)).divide(new BigDecimal(1000));//方法执行的时间 单位:秒
        LogVo logVo = LogThreadLocal.get();
        Map<String, String> exeTimeMap=LogThreadLocal.get().getExeTime();
        exeTimeMap.put(request.getRequestURI(),exeTime+"秒");
        logVo.setExeTime(exeTimeMap);
        log.info("此次{"+request.getRequestURI()+"}接口的完整日志为:"+JSONObject.toJSONString(LogThreadLocal.get()));
        return proceed;
    }

    @Pointcut("execution(* com.chenl.provider.feign..*(..))")
    public void feignInterfacePointCut() {}

    /**
     * feign调用切面,返回时通过feign.Response拿到响应头,设置到ThreadLocal中
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around(value = "feignInterfacePointCut()")
    public Object aroundFeignInterfaceMethod(ProceedingJoinPoint joinPoint) throws Throwable{
        feign.Response proceed = (Response) joinPoint.proceed();
        List<String> stringCollection = (List<String>) proceed.headers().get("log");
        String s = stringCollection.get(0);
        String logStr = URLDecoder.decode(s);
        if (StringUtils.isNotBlank(logStr)){
            LogVo logVo = JSONObject.parseObject(logStr, LogVo.class);
            LogThreadLocal.set(logVo);
        }
        return proceed;
    }
}
